home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / pc / SLOWRUNS.ZIP / SLOWSRC.ZIP / MAGIC4.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-28  |  62.3 KB  |  2,386 lines

  1. #include<io.h>
  2. #include<conio.h>
  3. #include<stdio.h>
  4. #include<stdlib.h>
  5. #include<dos.h>
  6. #include<bios.h>
  7. #include<fcntl.h>
  8. #include<memory.h>
  9. #include<malloc.h>
  10. #include<math.h>
  11. #include<string.h>
  12.  
  13. #include "magic3.h"
  14. #include "magic4.h"
  15.  
  16. // G L O B A L S  ////////////////////////////////////////////////////////////
  17.  
  18. // default sprite width and height
  19.  
  20. unsigned int sprite_width         = SPRITE_WIDTH;
  21.  
  22. unsigned int sprite_height        = SPRITE_HEIGHT;
  23.  
  24. unsigned char far *double_buffer  = NULL;  // the double buffer
  25.  
  26. // the default dimensions of the double buffer
  27.  
  28. unsigned int double_buffer_height = SCREEN_HEIGHT;
  29.  
  30. // size of double buffer in WORDS
  31.  
  32. unsigned int double_buffer_size   = SCREEN_WIDTH*SCREEN_HEIGHT/2;
  33.  
  34. // MODE Z STUFF
  35.  
  36. unsigned char far *page_0_buffer  = (unsigned char far *)0xA0000000L;
  37.  
  38. unsigned char far *page_1_buffer  = (unsigned char far *)0xA0008000L;
  39.  
  40. int mode_z_page                   = PAGE_0;
  41.  
  42. // MODE Y STUFF
  43.  
  44. unsigned char far *pagey_0_buffer  = (unsigned char far *)0xA0000000L;
  45.  
  46. unsigned char far *pagey_1_buffer  = (unsigned char far *)0xA0004000L;
  47.  
  48. unsigned char far *pagey_2_buffer  = (unsigned char far *)0xA0008000L;
  49.  
  50. unsigned char far *pagey_3_buffer  = (unsigned char far *)0xA000C000L;
  51.  
  52. int mode_y_page                   = PAGE_0;
  53.  
  54. // "SLOW RUNNINGS" SPECIFIC STUFF
  55.  
  56. unsigned char far *never_displayed_buffer_mode_y = (unsigned char far *)0xA0008000L;
  57.  
  58. unsigned char far *never_prime = (unsigned char far *)0xA000C900L;
  59.  
  60. // F U N C T I O N S /////////////////////////////////////////////////////////
  61.  
  62. void Line_HDB(int x1,int x2,int y,int color)
  63. {
  64. // draw a horizontal line using the memset function
  65. // this function does not do clipping hence x1,x2 and y must all be within
  66. // the bounds of the screen
  67.  
  68. _fmemset((char far *)(double_buffer + ((y<<8) + (y<<6)) + x1),
  69.          (unsigned char)color,x2-x1+1);
  70.  
  71. } // end Line_HDB
  72.  
  73. //////////////////////////////////////////////////////////////////////////////
  74.  
  75. void Line_VDB(int y1,int y2,int x,int color)
  76. {
  77. // draw a vertical line, note that a memset function can no longer be
  78. // used since the pixel addresses are no longer contiguous in memory
  79. // note that the end points of the line must be on the screen
  80.  
  81. unsigned char far *start_offset; // starting memory offset of line
  82.  
  83. int index; // loop index
  84.  
  85. // compute starting position
  86.  
  87. start_offset = double_buffer + ((y1<<8) + (y1<<6)) + x;
  88.  
  89. for (index=0; index<=y2-y1; index++)
  90.     {
  91.     // set the pixel
  92.  
  93.     *start_offset = (unsigned char)color;
  94.  
  95.     // move downward to next line
  96.  
  97.     start_offset+=320;
  98.  
  99.     } // end for index
  100.  
  101. } // end Line_VDB
  102.  
  103. void Screen_Transition(int effect)
  104. {
  105.     // this function can be called to perform a myriad of screen transitions
  106.     // to the video buffer, note I have left one for you to create!
  107.  
  108.     int pal_reg;        // used as loop counter
  109.     long index;            // used as loop counter
  110.     RGB_color color;    // temporary
  111.  
  112.     // test which screen effect is being selected
  113.  
  114.     switch(effect)
  115.     {
  116.         case SCREEN_DARKNESS:
  117.         {
  118.             // fade to black
  119.  
  120.             for(index=0; index<20; index++)
  121.             {
  122.                 // loop thru all palette registers
  123.  
  124.                 for(pal_reg=0; pal_reg<255; pal_reg++)
  125.                 {
  126.                     // get the next color to fade
  127.  
  128.                     Read_Color_Reg(pal_reg,(RGB_color_ptr)&color);
  129.  
  130.                     // test if this color register is already black
  131.                     if (color.red > 4) color.red-=3;
  132.                     else
  133.                         color.red = 0;
  134.  
  135.                     if (color.green > 4) color.green-=3;
  136.                     else
  137.                         color.green = 0;
  138.  
  139.                     if (color.blue > 4) color.blue-=3;
  140.                     else
  141.                         color.blue = 0;
  142.  
  143.                     // set the color to a diminshed intensity
  144.  
  145.                     Write_Color_Reg(pal_reg,(RGB_color_ptr)&color);
  146.  
  147.                 } // end for pal reg
  148.  
  149.                 // wait a bit
  150.  
  151.                 Time_Delay(1);
  152.  
  153.             } // end for index
  154.  
  155.           }
  156.           break;
  157.  
  158.         case SCREEN_WHITENESS:
  159.         {
  160.             // fade to white
  161.  
  162.             for(index=0; index<20; index++)
  163.             {
  164.                 // loop thru all palette registers
  165.  
  166.                 for(pal_reg=0; pal_reg<255; pal_reg++)
  167.                 {
  168.                     // get the next color to fade
  169.  
  170.                     Read_Color_Reg(pal_reg,(RGB_color_ptr)&color);
  171.  
  172.                     color.red += 4;
  173.  
  174.                     // test if this color register is already white
  175.                     if (color.red > 63)
  176.                         color.red=63;
  177.  
  178.                     color.green += 4;
  179.  
  180.                     if (color.green > 63)
  181.                         color.green=63;
  182.  
  183.                     color.blue +=4;
  184.  
  185.                     if (color.blue > 63)
  186.                         color.blue=63;
  187.  
  188.                     // set the color to a brighter intensity
  189.  
  190.                     Write_Color_Reg(pal_reg,(RGB_color_ptr)&color);
  191.  
  192.                 } // end for pal reg
  193.  
  194.                 // wait a bit
  195.  
  196.                 Time_Delay(1);
  197.  
  198.             } // end for index
  199.  
  200.           }
  201.           break;
  202.  
  203.         case SCREEN_WARP:
  204.         {
  205.             // THIS ONE I'LL DO LATER!
  206.         }
  207.         break;
  208.  
  209.         case SCREEN_SWIPE_X:
  210.         {
  211.             // do a screen swipe from right to left, left to right
  212.  
  213.             for (index = 0; index < 160; index+=2)
  214.             {
  215.                 // use this as a 1/70th of second time delay
  216.  
  217.                 Wait_For_Vertical_Retrace();
  218.  
  219.                 // draw two vertical lines at opposite ends of the screen
  220.  
  221.                 Line_V(0,199,319-index,0);
  222.                 Line_V(0,199,index,0);
  223.                 Line_V(0,199,319-(index+1),0);
  224.                 Line_V(0,199,index+1,0);
  225.             } // end for index
  226.         }
  227.         break;
  228.  
  229.         case SCREEN_SWIPE_Y:
  230.         {
  231.             // do a screen swipe from top to bottom, bottom to top
  232.  
  233.             for (index = 0; index < 100; index+=2)
  234.             {
  235.                 // use this as a 1/70th of second time delay
  236.  
  237.                 Wait_For_Vertical_Retrace();
  238.  
  239.                 // draw two horizontal lines at opposite ends of the screen
  240.  
  241.                 Line_H(0,319,199-index,0);
  242.                 Line_H(0,319,index,0);
  243.                 Line_H(0,319,199-(index+1),0);
  244.                 Line_H(0,319,index+1,0);
  245.             } // end for index
  246.         }
  247.         break;
  248.  
  249.         case SCREEN_DISSOLVE:
  250.         {
  251.             // disolve the screen by plotting zillions of little black dots
  252.             for (index = 0; index <= 300000; index++)
  253.                 Write_Pixel(rand()%320, rand()%200, 0);
  254.            }
  255.            break;
  256.  
  257.         case FULL_SCREEN_DARKNESS:
  258.         {
  259.             // fade to black
  260.  
  261.             for(index=0; index<20; index++)
  262.             {
  263.                 // loop thru all palette registers
  264.  
  265.                 for(pal_reg=0; pal_reg<=255; pal_reg++)
  266.                 {
  267.                     // get the next color to fade
  268.  
  269.                     Read_Color_Reg(pal_reg,(RGB_color_ptr)&color);
  270.  
  271.                     // test if this color register is already black
  272.                     if (color.red > 4) color.red-=3;
  273.                     else
  274.                         color.red = 0;
  275.  
  276.                     if (color.green > 4) color.green-=3;
  277.                     else
  278.                         color.green = 0;
  279.  
  280.                     if (color.blue > 4) color.blue-=3;
  281.                     else
  282.                         color.blue = 0;
  283.  
  284.                     // set the color to a diminshed intensity
  285.  
  286.                     Write_Color_Reg(pal_reg,(RGB_color_ptr)&color);
  287.  
  288.                 } // end for pal reg
  289.  
  290.                 // wait a bit
  291.  
  292.                 Time_Delay(1);
  293.  
  294.             } // end for index
  295.  
  296.           }
  297.           break;
  298.  
  299.            default:break;
  300.  
  301.      } // end switch
  302. } // end Screen_Transition
  303.  
  304. int Create_Double_Buffer(int num_lines)
  305. {
  306.     // allocate enoughmemoryto hold the double buffer
  307.  
  308.     if ((double_buffer = (unsigned char far *)_fmalloc(SCREEN_WIDTH * (num_lines + 1))) == NULL)
  309.     {
  310.         printf("\nCouldn't allocate double buffer.");
  311.         return(0);
  312.     } // end if couldn't allocate
  313.  
  314.     // set the height of the buffer andcompute its size
  315.  
  316.     double_buffer_height = num_lines;
  317.     double_buffer_size = SCREEN_WIDTH * num_lines/2;
  318.  
  319.     // fill the buffer with black
  320.  
  321.     _fmemset(double_buffer,0,SCREEN_WIDTH * num_lines);
  322.  
  323.     // everything was O.K....
  324.  
  325.     return(1);
  326.  
  327. } // end Create_Double_Buffer
  328.  
  329. void Fill_Double_Buffer(int color)
  330. {
  331.     // this function fills in the double buffer with the sent color a WORD at
  332.     // a time
  333.  
  334.     _asm
  335.     {
  336.         mov cx,double_buffer_size    ; this is the size of buffer is WORDS
  337.         mov al,BYTE PTR color        ; move the color into al
  338.         mov ah,al                    ; move the color into ah
  339.         les di,double_buffer        ; es:di points to the double buffer
  340.         rep stosw                    ; fill all the words
  341.     } // end asm
  342. } // end Fill_Double_Buffer
  343.  
  344. void Display_Double_Buffer(unsigned char far *buffer, int y)
  345. {
  346.     // this function copies the double buffer into the video buffer at the
  347.     // starting y location
  348.  
  349.     _asm
  350.     {
  351.         push ds                        ; save DS on stack
  352.         mov cx,double_buffer_size    ; this is the size of buffer in WORDS
  353.         les di,video_buffer            ; es:di is destination of memory move
  354.         mov ax,320                    ; multiply y by 320 i.e. screen width
  355.         mul y
  356.         add di, ax                    ; add result to es:di
  357.         lds si,buffer                ; ds:si is source of memory move
  358.         rep movsw                    ; mov all the words
  359.         pop ds                        ; restore the data segment
  360.     } // end asm
  361. } // end Display_Double_Buffer
  362.  
  363. void Delete_Double_Buffer(void)
  364. {
  365.     // this function frees upthe memory allocated by the double buffer
  366.     // make sure to use FAR version
  367.  
  368.     if (double_buffer)
  369.         _ffree(double_buffer);
  370.  
  371. } // end Delete_Double_Buffer
  372.  
  373. void Bitmap_Put(bitmap_ptr image, unsigned char far *destination, int transparent)
  374. {
  375.     // this function draw a bitmap on the destination buffer which can
  376.     // be a double buffer or the video buffer
  377.  
  378.     int x,y,                        // looping variables
  379.         width,height;                // size of bitmap
  380.  
  381.     unsigned char far *bitmap_data;    // pointer to bitmap buffer
  382.     unsigned char far *dest_buffer; // pointer to destination buffer
  383.  
  384.     unsigned char pixel;            // current pixel value being processed
  385.  
  386.     // compute offset of bitmap in destination buffer. Note: all video or
  387.     // double buffers must be 320 bytes wide!
  388.  
  389.     dest_buffer = destination + (image->y << 8) + (image->y << 6) + image->x;
  390.  
  391.     // create aliases to variables so the structure doesn't need to be
  392.     // dereferenced continually
  393.  
  394.     height         = image->height;
  395.     width        = image->width;
  396.     bitmap_data = image->buffer;
  397.  
  398.     // test if transparency is on or off
  399.  
  400.     if (transparent)
  401.     {
  402.         // use version that will draw a transparent bitmap (slightly slower)
  403.         // draw each line of the bitmap
  404.  
  405.         for (y = 0; y<height; y++)
  406.         {
  407.             // copy the next row into the destination buffer
  408.  
  409.             for (x = 0; x<width; x++)
  410.             {
  411.                 // test for transparent pixel i.e. 0, if not transparent then draw
  412.  
  413.                 if ((pixel=bitmap_data[x]))
  414.                     dest_buffer[x] = pixel;
  415.  
  416.             } // end for x
  417.  
  418.             // move to next line in double buffer and in bitmap buffer
  419.  
  420.             dest_buffer += SCREEN_WIDTH;
  421.             bitmap_data += width;
  422.  
  423.         } // end for y
  424.     } // end if transparent
  425.  
  426.     else
  427.     {
  428.         // draw each line of the bitmap, note how each pixel doesn't need to be
  429.         // tested for transparency hence a memcpy can be used (ver fast!)
  430.  
  431.         for (y = 0; y<height; y++)
  432.         {
  433.             // copy the next row into the destination buffer using memcpy for speed
  434.  
  435.             _fmemcpy((void far *)dest_buffer, (void far *)bitmap_data, width);
  436.  
  437.             // move to next line in destination buffer and in bitmap buffer
  438.  
  439.             dest_buffer += SCREEN_WIDTH;
  440.             bitmap_data += width;
  441.         } // end for y
  442.     } // end else non-transparent version
  443.  
  444. } // end Bitmap_Put
  445.  
  446. void Bitmap_Get(bitmap_ptr image, unsigned char far *source)
  447. {
  448.     // this function will scan a bitmap from the source buffer
  449.     // could be a double buffer, video buffer or any other buffer with
  450.     // logical row width of 320 bytes
  451.  
  452.     unsigned int source_off,            // offsets into destination and source buffers
  453.                  bitmap_off;
  454.  
  455.     int y,                                // looping variable
  456.         width,height;                    // size of bitmap
  457.  
  458.     unsigned char far *bitmap_data;        // pointer to bitmap buffer
  459.  
  460.     // compute offset of bitmap in source buffer. Note: all video or double
  461.     // buffers must be 320 bytes wide!
  462.  
  463.     source_off    = (image->y << 8) + (image->y << 6) + image->x;
  464.     bitmap_off    = 0;
  465.  
  466.     // create aliases to variable so the structure doesn't need to be
  467.     // dereferenced continually
  468.  
  469.     height         = image->height;
  470.     width        = image->width;
  471.     bitmap_data = image->buffer;
  472.  
  473.     // data each line of the bitmap, note now each pixel doesn't need to be
  474.     // tested for transparency hence a memcpy can be used (very fast!)
  475.  
  476.     for (y=0; y<height; y++)
  477.     {
  478.         // copy the next row into the bitmap buffer using memcpy for speed
  479.  
  480.         _fmemcpy((void far *)&bitmap_data[bitmap_off],(void far *)&source[source_off],width);
  481.  
  482.         // move to next line in source buffer and in bitmap buffer
  483.  
  484.         source_off += SCREEN_WIDTH;
  485.         bitmap_off += width;
  486.     } // end for y
  487.  
  488. } // end Bitmap_Get
  489.  
  490. int PCX_Init(pcx_picture_ptr image)
  491. {
  492.     // this function allocates the buffer that the image data will be loaded into
  493.     // when a PCX file is decompressed
  494.  
  495.     if (!(image->buffer = (unsigned char far *)_fmalloc(SCREEN_WIDTH * SCREEN_HEIGHT + 1)))
  496.     {
  497.         printf("\nPCX SYSTEM - Couldn't allocate PCX image buffer");
  498.         return(0);
  499.     } // end if
  500.  
  501.     // success
  502.  
  503.     return(1);
  504. } // end PCX_Init
  505.  
  506. void PCX_Delete(pcx_picture_ptr image)
  507. {
  508.     // this function de-allocates the buffer region used for the pcx file load
  509.  
  510.     _ffree(image->buffer);
  511.  
  512. } // end PCX_Delete
  513.  
  514. int PCX_Load(char *filename, pcx_picture_ptr image, int load_palette)
  515. {
  516.     // this function loads a PCX file into the image structure. The function
  517.     // has three main parts: 1. Load the PCX header, 2. Load the image data and
  518.     // decompress it and 3. Load the palette data and update the VGA palette
  519.     // note: the palette will only be laoded if the load_palette flag is 1
  520.  
  521.     FILE *fp;                        // the file poiinter used to open the PCX file
  522.  
  523.     int num_bytes,                    // number of bytes in current RLE run
  524.         index;                        // loop variable
  525.  
  526.     long count;                        // the total number of bytes decompressed
  527.     unsigned char data;                // the current pixel data
  528.     char far *temp_buffer;            // working buffer
  529.  
  530.     // open the file, test if it exists
  531.  
  532.     if ((fp = fopen(filename,"rb")) == NULL)
  533.     {
  534.         printf("/nPCX SYSTEM - Couldn't find file: %s", filename);
  535.         return(0);
  536.     } // end if couldn't find file
  537.  
  538.     // load the header
  539.  
  540.     temp_buffer = (char far *)image;
  541.  
  542.     for (index = 0; index<128; index++)
  543.     {
  544.         temp_buffer[index] = (char)getc(fp);
  545.     } // end for index
  546.  
  547.     // load the data and decompress into buffer, we need a total of 64,000 bytes
  548.  
  549.     count = 0;
  550.  
  551.     // loop while 64,000 bytes haven't been decompressed
  552.  
  553.     while(count<=SCREEN_WIDTH * SCREEN_HEIGHT)
  554.     {
  555.         // get the first piece of data
  556.  
  557.         data = (unsigned char)getc(fp);
  558.  
  559.         // is this a RLE run?
  560.         if (data>=192 && data<=255)
  561.         {
  562.             // compute number of bytes in run
  563.  
  564.             num_bytes = data-192;
  565.  
  566.             // get the actual data for the run
  567.  
  568.             data = (unsigned char)getc(fp);
  569.  
  570.             // replicate data in buffer num_bytes times
  571.  
  572.             while(num_bytes-->0)
  573.             {
  574.                 image->buffer[count++] = data;
  575.             } // end while
  576.  
  577.         } // end if rle
  578.  
  579.         else
  580.         {
  581.             // actual data, just copy it into buffer at next location
  582.  
  583.             image->buffer[count++] = data;
  584.  
  585.         } // end else not rle
  586.  
  587.     } // end while
  588.  
  589.     // load color palette
  590.  
  591.     // move to end of file then back up 768 bytes i.e. to beginning of palette
  592.  
  593.     fseek(fp,-768L,SEEK_END);
  594.  
  595.     // load the PCX palette into the VGA color registers
  596.  
  597.     for (index=0; index<256; index++)
  598.     {
  599.         // get the red component
  600.  
  601.         image->palette[index].red     = (unsigned char)(getc(fp) >> 2);
  602.  
  603.         // get the green component
  604.  
  605.         image->palette[index].green = (unsigned char)(getc(fp) >> 2);
  606.  
  607.         // get the blue component
  608.  
  609.         image->palette[index].blue     = (unsigned char)(getc(fp) >> 2);
  610.  
  611.     } // end for index
  612.  
  613.     // time to close the file
  614.  
  615.     fclose(fp);
  616.  
  617.     // change the palette to newly loaded palette if comanded to do so
  618.  
  619.     if (load_palette)
  620.     {
  621.         // for each palette register set to the new color values
  622.  
  623.         for (index = 0; index < 256; index++)
  624.         {
  625.             Write_Color_Reg(index,(RGB_color_ptr)&image->palette[index]);
  626.         } // end for index
  627.  
  628.     } // end if load palette data into VGA
  629.  
  630.     // success
  631.  
  632.     return(1);
  633.  
  634. } // end PCX_Load
  635.  
  636. void PCX_Show_Buffer(pcx_picture_ptr image)
  637. {
  638.     // copy the pcx buffer into the video buffer
  639.  
  640.     char far *data; // temp variable used for aliasing
  641.  
  642.     // alias image buffer
  643.  
  644.     data = image->buffer;
  645.  
  646.     // use inline assembly for speed
  647.  
  648.     _asm
  649.     {
  650.         push ds                    ; save the data segment
  651.         les di,video_buffer        ; point es:di to video buffer
  652.         lds si,data                ; point ds:si to data area
  653.         mov cx,320*200/2        ; move 32000 words
  654.         cld                        ; set direction to forward
  655.         rep movsw                ; do the string operation
  656.         pop ds                    ; restore the data segment
  657.     } // end inline asm
  658.  
  659. } // end PCX_Show_Buffer
  660.  
  661. void Sprite_Init(sprite_ptr sprite, int x, int y, int width, int height, int c1, int c2, int c3, int t1, int t2, int t3)
  662. {
  663.     // this function initializes a sprite
  664.  
  665.     int index;
  666.  
  667.     sprite->x            = x;
  668.     sprite->y            = y;
  669.     sprite->width        = width;
  670.     sprite->height        = height;
  671.     sprite->visible        = 1;
  672.     sprite->counter_1    = c1;
  673.     sprite->counter_2    = c2;
  674.     sprite->counter_3    = c3;
  675.     sprite->threshold_1 = t1;
  676.     sprite->threshold_2    = t2;
  677.     sprite->threshold_3 = t3;
  678.     sprite->curr_frame    = 0;
  679.     sprite->state        = SPRITE_DEAD;
  680.     sprite->num_frames    = 0;
  681.     sprite->background  = (unsigned char far *)_fmalloc(width * height+1);
  682.  
  683.     // set all bitmap pointers to null
  684.  
  685.     for (index = 0; index < MAX_SPRITE_FRAMES; index++)
  686.         sprite->frames[index] = NULL;
  687.  
  688. } // end Sprite_Init
  689.  
  690. void Sprite_Delete(sprite_ptr sprite)
  691. {
  692.     // this function dletes all the memory associated with a sprite
  693.  
  694.     int index;
  695.  
  696.     _ffree(sprite->background);
  697.  
  698.     // now de-allocate all the animation frames
  699.  
  700.     for (index = 0; index < MAX_SPRITE_FRAMES; index++)
  701.         _ffree(sprite->frames[index]);
  702.  
  703. } // end Sprite_Delete
  704.  
  705. void PCX_Get_Sprite(pcx_picture_ptr  image, sprite_ptr sprite, int sprite_frame, int cell_x, int cell_y)
  706. {
  707.     // this function is used to load the images for a sprite into the sprite
  708.     // frames array. It functions by using the size of the sprite and the
  709.     // position of the requested cell to compute the proper location in the
  710.     // pcx image buffer to extract the data from.
  711.  
  712.     int x_off,     // position of sprite cell in PCX image buffer
  713.         y_off,
  714.         y,        // looping variable
  715.         width,    // size of sprite
  716.         height;
  717.  
  718.     unsigned char far *sprite_data;
  719.  
  720.     // extract width and height of sprite
  721.  
  722.     width     = sprite->width;
  723.     height  = sprite->height;
  724.  
  725.     // first allocate the memory for the sprite in the sprite structure
  726.  
  727.     sprite->frames[sprite_frame] = (unsigned char far *)_fmalloc(width * height + 1);
  728.  
  729.     // create an alias to the sprite frame for ease of access
  730.  
  731.     sprite_data = sprite->frames[sprite_frame];
  732.  
  733.     // now load the sprite data into the sprite frame array from the pcx
  734.     // picture
  735.  
  736.     x_off = (width+1)    * cell_x + 1;
  737.     y_off = (height+1)  * cell_y + 1;
  738.  
  739.     // compute starting y address
  740.  
  741.     y_off = y_off * 320;    // 320 bytes per line
  742.  
  743.     // scan the data row by row
  744.  
  745.     for (y=0; y<height; y++,y_off+=320)
  746.     {
  747.         // copy the row of pixels
  748.  
  749.         _fmemcpy((void far *)&sprite_data[y*width],(void far *)&(image->buffer[y_off + x_off]), width);
  750.     } // end for y
  751.  
  752.     // increment number of frames
  753.  
  754.     sprite->num_frames++;
  755.  
  756.     // done!, let's bail!
  757. } // end PCX_Get_Sprite
  758.  
  759. void Sprite_Draw(sprite_ptr sprite, unsigned char far *buffer, int transparent)
  760. {
  761.     // this function draw a sprite on the screen row by row very quickly
  762.     // note the use of shifting to implement multiplication
  763.     // if the transparent flag is true the pixels will be drawn one by one
  764.     // else a memcpy will be used to draw each line
  765.  
  766.     unsigned char far *sprite_data; // pointer to sprite data
  767.     unsigned char far *dest_buffer; // pointer to destination buffer
  768.  
  769.     int x,y,                        // looping variables
  770.         width,                        // width of sprite
  771.         height;                        // height of sprite
  772.  
  773.     unsigned char pixel;            // the current pixel being processed
  774.  
  775.     // alias a pointer to sprite for ease of access
  776.  
  777.     sprite_data = sprite->frames[sprite->curr_frame];
  778.  
  779.     // alias a variable to sprite size
  780.  
  781.     width  = sprite->width;
  782.     height = sprite->height;
  783.  
  784.     // compute number of bytes between adjacent video lines after a row of pixels
  785.     // has been drawn
  786.  
  787.     // compute offset of sprite in destination buffer
  788.  
  789.     dest_buffer = buffer + (sprite->y << 8) + (sprite->y << 6) + sprite->x;
  790.  
  791.     // copy each line of the sprite data into destination buffer
  792.  
  793.     if (transparent)
  794.     {
  795.         for (y=0; y<height; y++)
  796.         {
  797.             // copy the next row into the destination buffer
  798.  
  799.             for (x=0; x<width; x++)
  800.             {
  801.                 // test for transparent pixel i.e. 0, if not transparent then draw
  802.  
  803.                 if ((pixel=sprite_data[x]))
  804.                     dest_buffer[x] = pixel;
  805.  
  806.             } // end for x
  807.  
  808.             // move to next line in destination buffer and sprite image buffer
  809.  
  810.             dest_buffer += SCREEN_WIDTH;
  811.             sprite_data += width;
  812.  
  813.         } // end for y
  814.     } // end if transparent
  815.  
  816.     else
  817.     {
  818.         // draw sprite with transparency off
  819.  
  820.         for (y=0; y<height; y++)
  821.         {
  822.             // copy the next row into the destination buffer
  823.  
  824.             _fmemcpy((void far *)dest_buffer, (void far *)sprite_data, width);
  825.  
  826.             // move to next line in destination buffer and sprite image buffer
  827.  
  828.             dest_buffer += SCREEN_WIDTH;
  829.             sprite_data += width;
  830.  
  831.         } // end for y
  832.     } // end else
  833.  
  834. } // end Sprite_Draw
  835.  
  836. void Sprite_Under(sprite_ptr sprite, unsigned char far *buffer)
  837. {
  838.     // this function scans the background under a sprite so that when the sprite
  839.     // is drawn the background isn't obliterated
  840.  
  841.     unsigned char far *back_buffer;        // background buffer for sprite
  842.  
  843.     int y,                                // current line being scanned
  844.         width,                            // size of sprite
  845.         height;
  846.  
  847.     // alias a pointer to sprite background for ease of access
  848.  
  849.     back_buffer = sprite->background;
  850.  
  851.     // alias width and height
  852.  
  853.     width  = sprite->width;
  854.     height = sprite->height;
  855.  
  856.     // compute offset of background in source buffer
  857.  
  858.     buffer = buffer + (sprite->y << 8) + (sprite->y << 6) + sprite->x;
  859.  
  860.     for (y=0; y<height; y++)
  861.     {
  862.         // copy the next row out of image buffer into sprite background buffer
  863.  
  864.         _fmemcpy((void far *)back_buffer, (void far *)buffer, width);
  865.  
  866.         // move to next line in source buffer and in sprite background buffer
  867.  
  868.         buffer        += SCREEN_WIDTH;
  869.         back_buffer += width;
  870.     } // end for y
  871. } // end Sprite_Under
  872.  
  873. void Sprite_Erase(sprite_ptr sprite, unsigned char far *buffer)
  874. {
  875.     // replace the background that was behind the sprite
  876.     // this function replaces the background that was saved from where a sprite
  877.     // was going to be placed
  878.  
  879.     unsigned char far *back_buffer;    // background buffer for sprite
  880.  
  881.     int    y,                            // current line being scanned
  882.         width,                        // size of sprite
  883.         height;
  884.  
  885.     // alias a pointer to sprite background for ease of access
  886.  
  887.     back_buffer = sprite->background;
  888.  
  889.     // alias width and height
  890.  
  891.     width  = sprite->width;
  892.     height = sprite->height;
  893.  
  894.     // compute offset in destination buffer
  895.  
  896.     buffer = buffer + (sprite->y << 8) + (sprite->y << 6) + sprite->x;
  897.  
  898.     for (y=0; y<height; y++)
  899.     {
  900.         // copy the next from sprite backgroundbuffer to destination buffer
  901.  
  902.         _fmemcpy((void far *)buffer, (void far *)back_buffer, width);
  903.  
  904.         // move to next line in destination buffer and in sprite background buffer
  905.  
  906.         buffer      += SCREEN_WIDTH;
  907.         back_buffer += width;
  908.  
  909.     } // end for y
  910. } // end Sprite_Erase
  911.  
  912. void PCX_Copy_To_Buffer(pcx_picture_ptr image, unsigned char far *buffer)
  913. {
  914.     // this function is used to copy the data in the PCX buffer to another buffer
  915.     // usually the double buffer
  916.  
  917.     // use the word copy function, note: double_buffer_size is in WORDS
  918.  
  919.     fwordcpy((void far *)buffer,(void far *)image->buffer,double_buffer_size);
  920.  
  921. } // end PCX_Copy_To_Buffer
  922.  
  923. void PCX_Copy_To_Buffer_XYZ_Mode(pcx_picture_ptr image, unsigned char far *buffer)
  924. {
  925.     // this function is used to copy the data in the PCX buffer to video memory
  926.     // in planar modes - X, Y, and Z!
  927.  
  928.     // The Width and Height is assumed to be 320x200 here...
  929.     //            because it's being developed for mode Y!
  930.  
  931.     int x_index;
  932.     int y_index;
  933.     unsigned int image_buffer_offset;
  934.     unsigned int vid_offset;
  935.  
  936.     for (x_index = 0; x_index<320; x_index++)
  937.     {
  938.         // first select the proper color plane to write to...
  939.         // I could have written to one plane at a time but - Oh Hell!...
  940.  
  941.         _asm
  942.         {
  943.            mov dx,SEQUENCER          ; address the sequencer
  944.            mov al,SEQ_PLANE_ENABLE   ; select the plane enable register
  945.            mov cl,BYTE PTR x_index   ; extract lower byte from x
  946.            and cl,03h                ; extract the plane number = x MOD 4
  947.            mov ah,1                  ; a "1" selects the plane in the plane enable
  948.            shl ah,cl                 ; shift the "1" bit proper number of times
  949.            out dx,ax                 ; do it baby!
  950.         } // end asm
  951.  
  952.         for (y_index = 0; y_index<200; y_index++)
  953.         {
  954.             image_buffer_offset = (y_index<<8) + (y_index<<6) + x_index;
  955.  
  956.             vid_offset = (y_index<<6) + (y_index<<4) + (x_index>>2);
  957.  
  958.             video_buffer[vid_offset] = image->buffer[image_buffer_offset];
  959.         }
  960.     }
  961.  
  962. } // end PCX_Copy_To_Buffer_XYZ_Mode
  963.  
  964. void fwordcpy(void far *destination, void far *source, int num_words)
  965. {
  966.     // this function is similar to fmemcpy execpt that it moves data in words
  967.     // it is about 25% faster than memcpy which uses bytes
  968.  
  969.     _asm
  970.     {
  971.         push ds                    ; need to save segment registers i.e. ds
  972.         les di,destination        ; point es:di to destination of memory move
  973.         lds si,source            ; point ds:si to source of memory move
  974.         mov cx,num_words        ; move into cx the number of words to be moved
  975.         rep movsw                ; let the processor do the memory move
  976.         pop ds                    ; restore the ds segment register
  977.     } // end inline asm
  978. } // end fwordcpy
  979.  
  980. ////////////////////////////////////////////////////////////////////////////////
  981.  
  982. void fwordset(void far *destination, int color, int num_words)
  983. {
  984.     // this function is similar to fmemset except that it sets data in words
  985.     // it is about 25% faster than memset which uses bytes
  986.  
  987.     _asm
  988.     {
  989.         mov ax,WORD PTR color        ; move the color into ax
  990.          les di,destination        ; point es:di to destination of memory set
  991.         mov cx,num_words        ; move into cx the number of words to be set
  992.         rep stosw                ; let the processor do the memory set
  993.     } // end inline asm
  994. } // end fwordset
  995.  
  996. ////////////////////////////////////////////////////////////////////////////////
  997.  
  998. void Sprite_Under_Clip(sprite_ptr sprite, unsigned char far *buffer)
  999. {
  1000.  
  1001. // this function scans the background under a sprite, but only those
  1002. // portions that are visible
  1003.  
  1004. unsigned char far *back_buffer;   // pointer to sprite background buffer
  1005. unsigned char far *source_buffer; // pointer to source buffer
  1006.  
  1007. int x,y,                        // looping variables
  1008.      sx,sy,                      // position of sprite
  1009.     width,                      // width of sprite
  1010.     bitmap_width  =0,           // width and height of sub-bitmap
  1011.     bitmap_height =0;
  1012.  
  1013. unsigned char pixel;            // the current pixel being processed
  1014.  
  1015. // alias a variable to sprite size
  1016.  
  1017. width         = sprite->width;
  1018. bitmap_width  = width;
  1019. bitmap_height = sprite->height;
  1020. sx            = sprite->x;
  1021. sy            = sprite->y;
  1022.  
  1023. // perform trivial rejection tests
  1024.  
  1025. if (sx >= (int)SCREEN_WIDTH || sy >= (int)double_buffer_height ||
  1026.    (sx+width) <= 0          || (sy+bitmap_height) <= 0)
  1027.    {
  1028.    // sprite is totally invisible therefore don't scan
  1029.  
  1030.    // set invisible flag in strucuture so that the draw sub-function
  1031.    // doesn't do anything
  1032.  
  1033.    sprite->visible = 0;
  1034.  
  1035.    return;
  1036.  
  1037.    } // end if invisible
  1038.  
  1039. // the sprite background region must be clipped before scanning
  1040. // therefore compute visible portion
  1041.  
  1042. // first compute upper left hand corner of clipped sprite background
  1043.  
  1044. if (sx<0)
  1045.    {
  1046.  
  1047.    bitmap_width += sx;
  1048.     sx            = 0;
  1049.  
  1050.  
  1051.    } // end off left edge
  1052. else
  1053. if (sx+width>=(int)SCREEN_WIDTH)
  1054.    {
  1055.  
  1056.    bitmap_width  = (int)SCREEN_WIDTH-sx;
  1057.  
  1058.    } // end off right edge
  1059.  
  1060. // now process y
  1061.  
  1062. if (sy<0)
  1063.    {
  1064.  
  1065.    bitmap_height += sy;
  1066.    sy             = 0;
  1067.  
  1068.     } // end off top edge
  1069. else
  1070. if (sy+bitmap_height>=(int)double_buffer_height)
  1071.     {
  1072.  
  1073.    bitmap_height  = (int)double_buffer_height - sy;
  1074.  
  1075.    } // end off lower edge
  1076.  
  1077. // this point we know were to start scanning the bitmap i.e.
  1078. // sx,sy
  1079. // and we know the size of the bitmap to be scanned i.e.
  1080. // width,height, so plug it all into the rest of function
  1081.  
  1082. // compute number of bytes between adjacent video lines after a row of pixels
  1083. // has been drawn
  1084.  
  1085. // compute offset of sprite background in source buffer
  1086.  
  1087. source_buffer = buffer + (sy << 8) + (sy << 6) + sx;
  1088.  
  1089. // alias a pointer to sprite background
  1090.  
  1091. back_buffer = sprite->background;
  1092.  
  1093. for (y=0; y<bitmap_height; y++)
  1094.     {
  1095.     // copy the next row into the destination buffer
  1096.  
  1097.     _fmemcpy((void far *)back_buffer,(void far *)source_buffer,bitmap_width);
  1098.  
  1099.     // move to next line in desintation buffer and sprite image buffer
  1100.  
  1101.     source_buffer += SCREEN_WIDTH;
  1102.     back_buffer   += width;  // note this width is the actual width of the
  1103.                                       // entire bitmap NOT the visible portion
  1104.     } // end for y
  1105.  
  1106. // set variables in strucuture so that the erase sub-function can operate
  1107. // faster
  1108.  
  1109. sprite->x_clip      = sx;
  1110. sprite->y_clip      = sy;
  1111. sprite->width_clip  = bitmap_width;
  1112. sprite->height_clip = bitmap_height;
  1113. sprite->visible     = 1;
  1114.  
  1115. } // end Sprite_Under_Clip
  1116.  
  1117. //////////////////////////////////////////////////////////////////////////////
  1118.  
  1119. void Sprite_Erase_Clip(sprite_ptr sprite,unsigned char far *buffer)
  1120. {
  1121. // replace the background that was behind the sprite
  1122. // this function replaces the background that was saved from where a sprite
  1123. // was going to be placed
  1124.  
  1125. unsigned char far *back_buffer; // background buffer for sprite
  1126.  
  1127. int y,                          // current line being scanned
  1128.      width,                      // size of sprite background buffer
  1129.     bitmap_height,              // size of clipped bitmap
  1130.     bitmap_width;
  1131.  
  1132. // make sure sprite was visible
  1133.  
  1134. if (!sprite->visible)
  1135.     return;
  1136.  
  1137. // alias a pointer to sprite background for ease of access
  1138.  
  1139. back_buffer = sprite->background;
  1140.  
  1141. // alias width and height
  1142.  
  1143. bitmap_width  = sprite->width_clip;
  1144. bitmap_height = sprite->height_clip;
  1145. width         = sprite->width;
  1146.  
  1147. // compute offset in destination buffer
  1148.  
  1149. buffer = buffer + (sprite->y_clip << 8) + (sprite->y_clip << 6)
  1150.                 + sprite->x_clip;
  1151.  
  1152. for (y=0; y<bitmap_height; y++)
  1153.     {
  1154.     // copy the next row from sprite background buffer to destination buffer
  1155.  
  1156.     _fmemcpy((void far *)buffer,
  1157.              (void far *)back_buffer,
  1158.                  bitmap_width);
  1159.  
  1160.      // move to next line in destination buffer and in sprite background buffer
  1161.  
  1162.     buffer      += SCREEN_WIDTH;
  1163.     back_buffer += width;
  1164.  
  1165.     } // end for y
  1166.  
  1167. } // end Sprite_Erase_Clip
  1168.  
  1169. //////////////////////////////////////////////////////////////////////////////
  1170.  
  1171. void Sprite_Draw_Clip(sprite_ptr sprite, unsigned char far *buffer,int transparent)
  1172. {
  1173.  
  1174. // this function draws a sprite on the screen row by row very quickly
  1175. // note the use of shifting to implement multplication
  1176. // if the transparent flag is true then pixels wil be draw one by one
  1177. // else a memcpy will be used to draw each line
  1178. // this function also performs clipping. It will test if the sprite
  1179. // is totally visible/invisible and will only draw the portions that are visible
  1180.  
  1181. unsigned char far *sprite_data; // pointer to sprite data
  1182. unsigned char far *dest_buffer; // pointer to destination buffer
  1183.  
  1184. int x,y,                        // looping variables
  1185.     sx,sy,                      // position of sprite
  1186.     width,                      // width of sprite
  1187.     bitmap_x      =0,           // starting upper left corner of sub-bitmap
  1188.      bitmap_y      =0,           // to be drawn after clipping
  1189.     bitmap_width  =0,           // width and height of sub-bitmap
  1190.     bitmap_height =0;
  1191.  
  1192. unsigned char pixel;            // the current pixel being processed
  1193.  
  1194. // alias a variable to sprite size
  1195.  
  1196. width         = sprite->width;
  1197. bitmap_width  = width;
  1198. bitmap_height = sprite->height;
  1199. sx            = sprite->x;
  1200. sy            = sprite->y;
  1201.  
  1202. // perform trivial rejection tests
  1203.  
  1204. if (sx >= (int)SCREEN_WIDTH || sy >= (int)double_buffer_height ||
  1205.    (sx+width) <= 0          || (sy+bitmap_height) <= 0 || !sprite->visible)
  1206.    {
  1207.    // sprite is totally invisible therefore don't draw
  1208.  
  1209.    // set invisible flag in strucuture so that the erase sub-function
  1210.    // doesn't do anything
  1211.  
  1212.    sprite->visible = 0;
  1213.  
  1214.    return;
  1215.  
  1216.    } // end if invisible
  1217.  
  1218. // the sprite needs some clipping or no clipping at all, so compute
  1219. // visible portion of sprite rectangle
  1220.  
  1221. // first compute upper left hand corner of clipped sprite
  1222.  
  1223. if (sx<0)
  1224.     {
  1225.  
  1226.    bitmap_x      = -sx;
  1227.    sx            = 0;
  1228.    bitmap_width -= bitmap_x;
  1229.  
  1230.    } // end off left edge
  1231. else
  1232. if (sx+width>=(int)SCREEN_WIDTH)
  1233.     {
  1234.  
  1235.    bitmap_x      = 0;
  1236.    bitmap_width  = (int)SCREEN_WIDTH-sx;
  1237.  
  1238.    } // end off right edge
  1239.  
  1240. // now process y
  1241.  
  1242. if (sy<0)
  1243.    {
  1244.  
  1245.    bitmap_y       = -sy;
  1246.    sy             = 0;
  1247.     bitmap_height -= bitmap_y;
  1248.  
  1249.    } // end off top edge
  1250. else
  1251. if (sy+bitmap_height>=(int)double_buffer_height)
  1252.    {
  1253.  
  1254.    bitmap_y       = 0;
  1255.    bitmap_height  = (int)double_buffer_height - sy;
  1256.  
  1257.    } // end off lower edge
  1258.  
  1259. // this point we know were to start drawing the bitmap i.e.
  1260. // sx,sy
  1261. // and we know were in the data to extract the bitmap i.e.
  1262. // bitmap_x, bitmap_y,
  1263. // and finaly we know the size of the bitmap to be drawn i.e.
  1264. // width,height, so plug it all into the rest of function
  1265.  
  1266. // compute number of bytes between adjacent video lines after a row of pixels
  1267. // has been drawn
  1268.  
  1269. // compute offset of sprite in destination buffer
  1270.  
  1271. dest_buffer = buffer + (sy << 8) + (sy << 6) + sx;
  1272.  
  1273. // alias a pointer to sprite for ease of access and locate starting sub
  1274. // bitmap that will be drawn
  1275.  
  1276. sprite_data = sprite->frames[sprite->curr_frame] + (bitmap_y*width) + bitmap_x;
  1277.  
  1278. // copy each line of the sprite data into destination buffer
  1279.  
  1280. if (transparent)
  1281.    {
  1282.    for (y=0; y<bitmap_height; y++)
  1283.        {
  1284.        // copy the next row into the destination buffer
  1285.  
  1286.        for (x=0; x<bitmap_width; x++)
  1287.            {
  1288.  
  1289.            // test for transparent pixel i.e. 0, if not transparent then draw
  1290.  
  1291.            if ((pixel=sprite_data[x]))
  1292.                 dest_buffer[x] = pixel;
  1293.  
  1294.            } // end for x
  1295.  
  1296.        // move to next line in desintation buffer and sprite image buffer
  1297.  
  1298.        dest_buffer += SCREEN_WIDTH;
  1299.        sprite_data += width;   // note this width is the actual width of the
  1300.                                // entire bitmap NOT the visible portion
  1301.        } // end for y
  1302.  
  1303.    } // end if transparent
  1304. else
  1305.    {
  1306.    // draw sprite with transparency off
  1307.  
  1308.     for (y=0; y<bitmap_height; y++)
  1309.        {
  1310.        // copy the next row into the destination buffer
  1311.  
  1312.        _fmemcpy((void far *)dest_buffer,(void far *)sprite_data,bitmap_width);
  1313.  
  1314.        // move to next line in desintation buffer and sprite image buffer
  1315.  
  1316.        dest_buffer += SCREEN_WIDTH;
  1317.        sprite_data += width;  // note this width is the actual width of the
  1318.                               // entire bitmap NOT the visible portion
  1319.        } // end for y
  1320.  
  1321.    } // end else
  1322.  
  1323. // set variables in strucuture so that the erase sub-function can operate
  1324. // faster
  1325.  
  1326. sprite->x_clip      = sx;
  1327. sprite->y_clip      = sy;
  1328. sprite->width_clip  = bitmap_width;
  1329. sprite->height_clip = bitmap_height;
  1330. sprite->visible     = 1;
  1331.  
  1332. } // end Sprite_Draw_Clip
  1333.  
  1334. void Sprite_Draw_Clip_Special(sprite_ptr sprite, unsigned char far *buffer)
  1335. {
  1336.  
  1337.     // this function draws a sprite on the screen row by row very quickly
  1338.     // note the use of shifting to implement multplication
  1339.     // if the transparent flag is true then pixels wil be draw one by one
  1340.     // else a memcpy will be used to draw each line
  1341.     // this function also performs clipping. It will test if the sprite
  1342.     // is totally visible/invisible and will only draw the portions that are visible
  1343.  
  1344.     unsigned char far *sprite_data; // pointer to sprite data
  1345.     unsigned char far *dest_buffer; // pointer to destination buffer
  1346.  
  1347.     int x_factor,y_factor,                        // looping variables
  1348.         sx,sy,                      // position of sprite
  1349.         width,                      // width of sprite
  1350.         bitmap_x      =0,           // starting upper left corner of sub-bitmap
  1351.         bitmap_y      =0,           // to be drawn after clipping
  1352.         bitmap_width  =0,           // width and height of sub-bitmap
  1353.         bitmap_height =0;
  1354.  
  1355.     unsigned char pixel;            // the current pixel being processed
  1356.  
  1357.     // alias a variable to sprite size
  1358.  
  1359.     width         = sprite->width;
  1360.     bitmap_width  = width;
  1361.     bitmap_height = sprite->height;
  1362.     sx            = sprite->x;
  1363.     sy            = sprite->y;
  1364.  
  1365.     // perform trivial rejection tests
  1366.  
  1367.  
  1368.     // first compute upper left hand corner of clipped sprite
  1369.  
  1370.  
  1371.     // now process y
  1372.  
  1373.     if (sy<0)
  1374.     {
  1375.  
  1376.         bitmap_y       = -sy;
  1377.         sy             = 0;
  1378.         bitmap_height -= bitmap_y;
  1379.  
  1380.     } // end off top edge
  1381.     else
  1382.     if (sy+bitmap_height>=(int)200)
  1383.     {
  1384.  
  1385.         bitmap_y       = 0;
  1386.         bitmap_height  = (int)200 - sy;
  1387.  
  1388.     } // end off lower edge
  1389.  
  1390.     // this point we know were to start drawing the bitmap i.e.
  1391.     // sx,sy
  1392.     // and we know were in the data to extract the bitmap i.e.
  1393.     // bitmap_x, bitmap_y,
  1394.     // and finaly we know the size of the bitmap to be drawn i.e.
  1395.     // width,height, so plug it all into the rest of function
  1396.  
  1397.     // compute number of bytes between adjacent video lines after a row of pixels
  1398.     // has been drawn
  1399.  
  1400.     // compute offset of sprite in destination buffer
  1401.  
  1402.     _asm
  1403.     {
  1404.         mov dx,SEQUENCER          // address the sequencer
  1405.         mov al,SEQ_PLANE_ENABLE   // select the plane enable register
  1406.         mov ah,0x01                  // extract lower byte from x_factor
  1407.         out dx,ax                 // do it baby!
  1408.     } // end asm
  1409.  
  1410.     dest_buffer = buffer + (sy << 6) + (sy << 4) + (sx>>2);
  1411.  
  1412.     // alias a pointer to sprite for ease of access and locate starting sub
  1413.     // bitmap that will be drawn
  1414.  
  1415.     sprite_data = sprite->frames[sprite->curr_frame] + (bitmap_y*width) + bitmap_x;
  1416.  
  1417.     // copy each line of the sprite data into destination buffer
  1418.  
  1419.     for (y_factor=0; y_factor<bitmap_height; y_factor++)
  1420.     {
  1421.         // copy the next row into the destination buffer
  1422.  
  1423.         for (x_factor=0; x_factor<bitmap_width; x_factor+=4)
  1424.         {
  1425.  
  1426.             // test for transparent pixel i.e. 0, if not transparent then draw
  1427.  
  1428.             if ((pixel=sprite_data[x_factor]))
  1429.             dest_buffer[(x_factor>>2)] = pixel;
  1430.  
  1431.         } // end for x_factor
  1432.  
  1433.         // move to next line in desintation buffer and sprite image buffer
  1434.  
  1435.         dest_buffer += 80;
  1436.         sprite_data += width;   // note this width is the actual width of the
  1437.                             // entire bitmap NOT the visible portion
  1438.     } // end for y_factor
  1439.  
  1440.     _asm
  1441.     {
  1442.         mov dx,SEQUENCER          // address the sequencer
  1443.         mov al,SEQ_PLANE_ENABLE   // select the plane enable register
  1444.         mov ah,0x02                  // extract lower byte from x_factor
  1445.         out dx,ax                 // do it baby!
  1446.     } // end asm
  1447.  
  1448.     dest_buffer = buffer + (sy << 6) + (sy << 4) + (sx>>2);
  1449.  
  1450.     // alias a pointer to sprite for ease of access and locate starting sub
  1451.     // bitmap that will be drawn
  1452.  
  1453.     sprite_data = sprite->frames[sprite->curr_frame] + (bitmap_y*width) + bitmap_x;
  1454.  
  1455.     // copy each line of the sprite data into destination buffer
  1456.  
  1457.     for (y_factor=0; y_factor<bitmap_height; y_factor++)
  1458.     {
  1459.         // copy the next row into the destination buffer
  1460.  
  1461.         for (x_factor=0; x_factor<bitmap_width; x_factor+=4)
  1462.         {
  1463.  
  1464.             // test for transparent pixel i.e. 0, if not transparent then draw
  1465.  
  1466.             if ((pixel=sprite_data[x_factor+1]))
  1467.             dest_buffer[(x_factor>>2)] = pixel;
  1468.  
  1469.         } // end for x_factor
  1470.  
  1471.         // move to next line in desintation buffer and sprite image buffer
  1472.  
  1473.         dest_buffer += 80;
  1474.         sprite_data += width;   // note this width is the actual width of the
  1475.                             // entire bitmap NOT the visible portion
  1476.     } // end for y_factor
  1477.  
  1478.     _asm
  1479.     {
  1480.         mov dx,SEQUENCER          // address the sequencer
  1481.         mov al,SEQ_PLANE_ENABLE   // select the plane enable register
  1482.         mov ah,0x04                  // extract lower byte from x_factor
  1483.         out dx,ax                 // do it baby!
  1484.     } // end asm
  1485.  
  1486.     dest_buffer = buffer + (sy << 6) + (sy << 4) + (sx>>2);
  1487.  
  1488.     // alias a pointer to sprite for ease of access and locate starting sub
  1489.     // bitmap that will be drawn
  1490.  
  1491.     sprite_data = sprite->frames[sprite->curr_frame] + (bitmap_y*width) + bitmap_x;
  1492.  
  1493.     // copy each line of the sprite data into destination buffer
  1494.  
  1495.     for (y_factor=0; y_factor<bitmap_height; y_factor++)
  1496.     {
  1497.         // copy the next row into the destination buffer
  1498.  
  1499.         for (x_factor=0; x_factor<bitmap_width; x_factor+=4)
  1500.         {
  1501.  
  1502.             // test for transparent pixel i.e. 0, if not transparent then draw
  1503.  
  1504.             if ((pixel=sprite_data[x_factor+2]))
  1505.             dest_buffer[(x_factor>>2)] = pixel;
  1506.  
  1507.         } // end for x_factor
  1508.  
  1509.         // move to next line in desintation buffer and sprite image buffer
  1510.  
  1511.         dest_buffer += 80;
  1512.         sprite_data += width;   // note this width is the actual width of the
  1513.                             // entire bitmap NOT the visible portion
  1514.     } // end for y_factor
  1515.  
  1516.     _asm
  1517.     {
  1518.         mov dx,SEQUENCER          // address the sequencer
  1519.         mov al,SEQ_PLANE_ENABLE   // select the plane enable register
  1520.         mov ah,0x08                  // extract lower byte from x_factor
  1521.         out dx,ax                 // do it baby!
  1522.     } // end asm
  1523.  
  1524.     dest_buffer = buffer + (sy << 6) + (sy << 4) + (sx>>2);
  1525.  
  1526.     // alias a pointer to sprite for ease of access and locate starting sub
  1527.     // bitmap that will be drawn
  1528.  
  1529.     sprite_data = sprite->frames[sprite->curr_frame] + (bitmap_y*width) + bitmap_x;
  1530.  
  1531.     // copy each line of the sprite data into destination buffer
  1532.  
  1533.     for (y_factor=0; y_factor<bitmap_height; y_factor++)
  1534.     {
  1535.         // copy the next row into the destination buffer
  1536.  
  1537.         for (x_factor=0; x_factor<bitmap_width; x_factor+=4)
  1538.         {
  1539.  
  1540.             // test for transparent pixel i.e. 0, if not transparent then draw
  1541.  
  1542.             if ((pixel=sprite_data[x_factor+3]))
  1543.             dest_buffer[(x_factor>>2)] = pixel;
  1544.  
  1545.         } // end for x_factor
  1546.  
  1547.         // move to next line in desintation buffer and sprite image buffer
  1548.  
  1549.         dest_buffer += 80;
  1550.         sprite_data += width;   // note this width is the actual width of the
  1551.                             // entire bitmap NOT the visible portion
  1552.     } // end for y_factor
  1553.  
  1554. } // end Sprite_Draw_Clip_Special
  1555.  
  1556.  
  1557. int Layer_Create(layer_ptr dest_layer, int width, int height)
  1558. {
  1559.     // this function can be used to allocate the memory needed for a layer
  1560.     // the width must be divisible by 2
  1561.  
  1562.     if ((dest_layer->buffer = (unsigned char far *)_fmalloc(width*height+2))==NULL)
  1563.         return(0);
  1564.     else
  1565.     {
  1566.         // save the dimensions of layer
  1567.  
  1568.         dest_layer->width  = width;
  1569.         dest_layer->height = height;
  1570.  
  1571.         return(1);
  1572.     } // end else
  1573.  
  1574. } // end Layer_Create
  1575.  
  1576. void Layer_Delete(layer_ptr the_layer)
  1577. {
  1578.     // this function deletes the memory used by a layer
  1579.  
  1580.     if (the_layer->buffer)
  1581.         _ffree(the_layer->buffer);
  1582. } // end Layer_Delete
  1583.  
  1584. void Layer_Build(layer_ptr dest_layer, int dest_x, int dest_y, unsigned char far *source_buffer, int source_x, int source_y, int width, int height)
  1585. {
  1586.     // this function is used to build up the layer out of smaller pieces
  1587.     // this allows a layer to  be very long, tall etc. also the source data buffer
  1588.     // must be constructed such that there are 320 bytes per row
  1589.  
  1590.     int y,                                // looping variable
  1591.         layer_width;                    // the width of the layer
  1592.  
  1593.     unsigned char far *source_data;        // pointer to start of source bitmap image
  1594.     unsigned char far *layer_buffer;    // pointer to layer buffer
  1595.  
  1596.     // extract width of layer
  1597.  
  1598.     layer_width = dest_layer->width;
  1599.  
  1600.     // compute starting location in layer buffer
  1601.  
  1602.     layer_buffer = dest_layer->buffer + layer_width*dest_y + dest_x;
  1603.  
  1604.     // compute starting location in source image buffer
  1605.  
  1606.     source_data = source_buffer + (source_y << 8) + (source_y << 6) + source_x;
  1607.  
  1608.     // scan each line of source image into layer buffer
  1609.  
  1610.     for (y=0; y<height; y++)
  1611.     {
  1612.         // copy the next row into the layer buffer using memcpy for speed
  1613.  
  1614.         _fmemcpy((void far *)layer_buffer, (void far *)source_data, width);
  1615.  
  1616.         // move to next line in source buffer and in layer buffer
  1617.  
  1618.         source_data        +=SCREEN_WIDTH;
  1619.         layer_buffer    +=layer_width;
  1620.  
  1621.     } // end for y
  1622.  
  1623. } // end Layer_Build
  1624.  
  1625. void Layer_Draw(layer_ptr source_layer, int source_x, int source_y, unsigned char far *dest_buffer, int dest_y, int dest_height, int transparent)
  1626. {
  1627.     // this function will map down a section of the layer onto the destination
  1628.     // buffer at the desired location, note the width of the destination buffer
  1629.     // is always assumed to be 320 bytes width. Also, the function will always
  1630.     // wrap around the layer
  1631.  
  1632.     int x,y,                            // looping variables
  1633.         layer_width,                    // the width of the layer
  1634.         right_width,                    // the width of the right and left half of
  1635.         left_width;                        // the layer to be drawn
  1636.  
  1637.     unsigned char far *layer_buffer_l;    // pointers to the left and right halves
  1638.     unsigned char far *dest_buffer_l;    // of the layer buffer and destination
  1639.     unsigned char far *layer_buffer_r;    // buffer
  1640.     unsigned char far *dest_buffer_r;
  1641.  
  1642.     unsigned char pixel;                // current pixel value being processed
  1643.  
  1644.     layer_width      = source_layer->width;
  1645.     dest_buffer_l    = dest_buffer + (dest_y << 8) + (dest_y << 6);
  1646.     layer_buffer_l  = source_layer->buffer + layer_width*source_y + source_x;
  1647.  
  1648.     // test if wrapping is needed
  1649.  
  1650.     if (((layer_width-source_x) - (int)SCREEN_WIDTH) >= 0)
  1651.     {
  1652.         // there's enough data in layer to draw a complete line, no wrapping needed
  1653.  
  1654.         left_width  = SCREEN_WIDTH;
  1655.         right_width = 0; // no wrapping flag
  1656.     } // end if
  1657.     else
  1658.     {
  1659.         // wrapping needed
  1660.  
  1661.         left_width      = layer_width - source_x;
  1662.         right_width        = SCREEN_WIDTH - left_width;
  1663.         dest_buffer_r    = dest_buffer_l + left_width;
  1664.         layer_buffer_r    = layer_buffer_l - source_x; // move to far left end of layer
  1665.     } // end else need to wrap
  1666.  
  1667.     // test if transparency is on or off
  1668.  
  1669.     if (transparent)
  1670.     {
  1671.         // use this version that will draw a transparent bitmap (slightly slower)
  1672.         // first draw left half then right half
  1673.         // draw each line of the bitmap
  1674.  
  1675.         for (y=0; y<dest_height; y++)
  1676.         {
  1677.             // copy the next row into the destination buffer
  1678.  
  1679.             for (x=0; x<left_width; x++)
  1680.             {
  1681.                 // test for transparent pixel i.e. 0, if not transparent then draw
  1682.  
  1683.                 if ((pixel=layer_buffer_l[x]))
  1684.                     dest_buffer_l[x] = pixel;
  1685.  
  1686.             } // end for x
  1687.  
  1688.             // move to next line in destination buffer and in layer buffer
  1689.  
  1690.             dest_buffer_l      += SCREEN_WIDTH;
  1691.             layer_buffer_l  += layer_width;
  1692.         } // end for y
  1693.  
  1694.         // now right half
  1695.  
  1696.         // draw each line of the bitmap
  1697.  
  1698.         if (right_width)
  1699.         {
  1700.             for (y=0; y<dest_height; y++)
  1701.             {
  1702.                 // copy the next row into the destination buffer
  1703.  
  1704.                 for (x=0; x<right_width; x++)
  1705.                 {
  1706.                     // test for transparent pixel i.e. 0, if not transparent then draw
  1707.  
  1708.                     if ((pixel=layer_buffer_r[x]))
  1709.                         dest_buffer_r[x] = pixel;
  1710.  
  1711.                 } // end for x
  1712.  
  1713.                 // move to next line in destination buffer and in layer buffer
  1714.  
  1715.                 dest_buffer_r      += SCREEN_WIDTH;
  1716.                 layer_buffer_r  += layer_width;
  1717.             } // end for y
  1718.         } // end if right side needs to be drawn
  1719.  
  1720.     } // end if transparent
  1721.     else
  1722.     {
  1723.         // draw each line of the bitmap, note how each pixel doesn't need to be
  1724.         // test for transparency hence a memcpy can be used (very fast!)
  1725.  
  1726.         for (y=0; y<dest_height; y++)
  1727.         {
  1728.             // copy the next row into the destination buffer using memcpy for speed
  1729.  
  1730.             _fmemcpy((void far *)dest_buffer_l,(void far *)layer_buffer_l, left_width);
  1731.  
  1732.             // move to next line in double buffer and in bitmap buffer
  1733.  
  1734.             dest_buffer_l  += SCREEN_WIDTH;
  1735.             layer_buffer_l += layer_width;
  1736.         } // end for y
  1737.  
  1738.         // now right half if needed
  1739.  
  1740.         if (right_width)
  1741.         {
  1742.             for (y=0; y<dest_height; y++)
  1743.             {
  1744.                 // copy the next row into the destination buffer using memcpy for speed
  1745.  
  1746.                 _fmemcpy((void far *)dest_buffer_r,(void far *)layer_buffer_r, right_width);
  1747.  
  1748.                 // move to next line in double buffer and in bitmap buffer
  1749.  
  1750.                 dest_buffer_r  += SCREEN_WIDTH;
  1751.                 layer_buffer_r += layer_width;
  1752.             } // end for y
  1753.  
  1754.          } // end if right half
  1755.  
  1756.     } // end else non-transparent version
  1757.  
  1758. } // end Layer_Draw
  1759.  
  1760. void Wait_For_Vertical_Retrace(void)
  1761. {
  1762.     // this function waits for the start of a vertical retrace, if a vertical
  1763.     // retrace is in progress then it waits until the next one
  1764.     // therefore the function can wait a maximum of 2/70ths of a second
  1765.     // before returning
  1766.     // this function can be used to synchronize video updates to the vertical blank
  1767.     // or as a high resolution time reference
  1768.  
  1769.     while(_inp(VGA_INPUT_STATUS_1) & VGA_VRETRACE_MASK)
  1770.     {
  1771.         // do nothing, vga is already in retrace
  1772.     } // end while
  1773.  
  1774.     // now wait for start of vertical retrace and exit
  1775.  
  1776.     while(!(_inp(VGA_INPUT_STATUS_1) & VGA_VRETRACE_MASK))
  1777.     {
  1778.         // do nothing, wait for start of retrace
  1779.     } // end while
  1780.  
  1781.     // at this point a vertical retrace is occurring, so return back to caller
  1782.  
  1783. } // end Wait_For_Vertical_Retrace
  1784.  
  1785. void Print_Char_DB(int xc, int yc, char c, int color, int transparent)
  1786. {
  1787.     // this function is used to print a character on the screen. It uses the
  1788.     // internal 8x8 character set to do this. Note that each character is
  1789.     // 8 bytes where each byte represents the 8 pixels that make up the row
  1790.     // of pixels
  1791.  
  1792.     int offset,            // offset into video memory
  1793.         x,                // loop variable
  1794.         y;                // loop variable
  1795.  
  1796.     unsigned char far *work_char; // pointer to character being printed
  1797.  
  1798.     unsigned char bit_mask;          // bit mask used to extract proper bit
  1799.  
  1800.     // compute starting offset in rom character lookup table
  1801.     // multiply the character by 8 and add the result to the starting address
  1802.     // of the ROM character set
  1803.  
  1804.     work_char = rom_char_set + c * ROM_CHAR_HEIGHT;
  1805.  
  1806.     // compute offset of character in video buffer, use shifting to multiply
  1807.  
  1808.     offset = (yc << 8) + (yc << 6) + xc;
  1809.  
  1810.     // draw the character row by row
  1811.  
  1812.     for (y = 0; y < ROM_CHAR_HEIGHT; y++)
  1813.     {
  1814.         // reset bit mask
  1815.  
  1816.         bit_mask = 0x80;
  1817.  
  1818.         // draw each pixel of this row
  1819.  
  1820.         for (x = 0; x < ROM_CHAR_WIDTH; x++)
  1821.         {
  1822.             // test for transparent pixel i.e. 0, if not transparent then draw
  1823.  
  1824.             if ((*work_char & bit_mask))
  1825.                 double_buffer[offset+x] = (unsigned char)color;
  1826.  
  1827.             else
  1828.             if (!transparent)                // takes care of transparency
  1829.                 double_buffer[offset+x] = 0; // make black part opaque
  1830.  
  1831.             // shift bit mask
  1832.  
  1833.             bit_mask = (bit_mask>>1);
  1834.  
  1835.         } // end for x
  1836.  
  1837.         // move to next line in video buffer and in rom character data area
  1838.  
  1839.         offset += MODE13_WIDTH;
  1840.         work_char++;
  1841.     } // end for y
  1842. } // end Print_Char_DB
  1843.  
  1844. void Print_String_DB(int x, int y, int color, char *string, int transparent)
  1845. {
  1846.     // this function prints an entire string on the screen with fixed spacing
  1847.     // between each character by calling the Print_Char() function
  1848.  
  1849.     int index,    // loop index
  1850.         length; // length of string
  1851.  
  1852.     // compute length of string
  1853.  
  1854.     length = strlen(string);
  1855.  
  1856.     // print the string a character at a time
  1857.  
  1858.     for (index = 0; index<length; index ++)
  1859.         Print_Char_DB(x+(index<<3),y,string[index],color,transparent);
  1860.  
  1861. } // end Print_String_DB
  1862.  
  1863. void Write_Pixel_DB(int x, int y, int color)
  1864. {
  1865.  
  1866.     // plots the pixel in the desired color a little quicker using binary shifting
  1867.     // to accomplish the multiplications
  1868.  
  1869.     // uses the fact that 320*y = 256*y + 64*y = y<<8 + y<<6
  1870.  
  1871.     double_buffer[((y<<8) + (y<<6)) + x] = (unsigned char)color;
  1872.  
  1873. } // end Write_Pixel_DB
  1874.  
  1875. int Read_Pixel_DB(int x, int y)
  1876. {
  1877.     // This function reads a pixel from the screen buffer
  1878.  
  1879.     return((int)(double_buffer[((y<<8) + (y<<6)) + x]));
  1880.  
  1881. }
  1882.  
  1883. void Set_Visual_Page_Mode_Z(int page)
  1884. {
  1885. // this function sets the visual page that will be displayed by the VGA
  1886.  
  1887. if (page==PAGE_0)
  1888.    {
  1889.    // re-program the start address registers in the CRT controller
  1890.    // to point at page 0 @ 0xA000:0000
  1891.  
  1892.    // first low byte of address
  1893.  
  1894.    _outp(CRT_CONTROLLER,CRT_ADDR_LOW);
  1895.    _outp(CRT_CONTROLLER+1,0x00);
  1896.  
  1897.    // now high byte
  1898.  
  1899.    _outp(CRT_CONTROLLER,CRT_ADDR_HI);
  1900.    _outp(CRT_CONTROLLER+1,0x00);
  1901.  
  1902.    } // end if page 0
  1903. else
  1904. if (page==PAGE_1)
  1905.    {
  1906.    // re-program the start address registers in the CRT controller
  1907.    // to point at page 1 @ 0xA000:8000
  1908.  
  1909.    // first low byte of address
  1910.  
  1911.    _outp(CRT_CONTROLLER,CRT_ADDR_LOW);
  1912.    _outp(CRT_CONTROLLER+1,0x00);
  1913.  
  1914.    // now high byte
  1915.  
  1916.    _outp(CRT_CONTROLLER,CRT_ADDR_HI);
  1917.    _outp(CRT_CONTROLLER+1,0x80);
  1918.  
  1919.    } // end else page 1
  1920.  
  1921. // note: we could use WORD out's, but this is clearer, feel free to change them
  1922.  
  1923. } // end Set_Visual_Page_Mode_Z
  1924.  
  1925. ///////////////////////////////////////////////////////////////////////////////
  1926.  
  1927. void Set_Visual_Page_Mode_Z_Half(int page)
  1928. {
  1929. // THIS VERSION OF THE FUNCTION SAVES AN OUTS WORTH OF COMPUTER CYCLES!!!
  1930.  
  1931. // this function sets the visual page that will be displayed by the VGA
  1932.  
  1933. if (page==PAGE_0)
  1934.    {
  1935.    // re-program the start address registers in the CRT controller
  1936.    // to point at page 0 @ 0xA000:0000
  1937.  
  1938.    // first low byte of address
  1939.  
  1940. //   _outp(CRT_CONTROLLER,CRT_ADDR_LOW);
  1941. //   _outp(CRT_CONTROLLER+1,0x00);
  1942.  
  1943.    // now high byte
  1944.  
  1945.    _outp(CRT_CONTROLLER,CRT_ADDR_HI);
  1946.    _outp(CRT_CONTROLLER+1,0x00);
  1947.  
  1948.    } // end if page 0
  1949. else
  1950. if (page==PAGE_1)
  1951.    {
  1952.    // re-program the start address registers in the CRT controller
  1953.    // to point at page 1 @ 0xA000:8000
  1954.  
  1955.    // first low byte of address
  1956.  
  1957. //   _outp(CRT_CONTROLLER,CRT_ADDR_LOW);
  1958. //   _outp(CRT_CONTROLLER+1,0x00);
  1959.  
  1960.    // now high byte
  1961.  
  1962.    _outp(CRT_CONTROLLER,CRT_ADDR_HI);
  1963.    _outp(CRT_CONTROLLER+1,0x80);
  1964.  
  1965.    } // end else page 1
  1966.  
  1967. // note: we could use WORD out's, but this is clearer, feel free to change them
  1968.  
  1969. } // end Set_Visual_Page_Mode_Z
  1970.  
  1971. ///////////////////////////////////////////////////////////////////////////////
  1972. void Set_Working_Page_Mode_Z(int page)
  1973. {
  1974. // this function sets the page that all mode Z functions will update when
  1975. // called
  1976.  
  1977. if (page==PAGE_0)
  1978.    video_buffer = page_0_buffer;
  1979. else
  1980.    video_buffer = page_1_buffer;
  1981.  
  1982. } // end Set_Working_Page_Mode_Z
  1983.  
  1984. void Set_Visual_Page_Mode_Y(int page)
  1985. {
  1986. // this function sets the visual page that will be displayed by the VGA
  1987.  
  1988. if (page==PAGE_0)
  1989.    {
  1990.    // re-program the start address registers in the CRT controller
  1991.    // to point at page 0 @ 0xA000:0000
  1992.  
  1993.    // first low byte of address
  1994.  
  1995.    _outp(CRT_CONTROLLER,CRT_ADDR_LOW);
  1996.    _outp(CRT_CONTROLLER+1,0x00);
  1997.  
  1998.    // now high byte
  1999.  
  2000.    _outp(CRT_CONTROLLER,CRT_ADDR_HI);
  2001.    _outp(CRT_CONTROLLER+1,0x00);
  2002.  
  2003.    } // end if page 0
  2004. else
  2005. if (page==PAGE_1)
  2006.    {
  2007.    // re-program the start address registers in the CRT controller
  2008.    // to point at page 1 @ 0xA000:4000
  2009.  
  2010.    // first low byte of address
  2011.  
  2012.    _outp(CRT_CONTROLLER,CRT_ADDR_LOW);
  2013.    _outp(CRT_CONTROLLER+1,0x00);
  2014.  
  2015.    // now high byte
  2016.  
  2017.    _outp(CRT_CONTROLLER,CRT_ADDR_HI);
  2018.    _outp(CRT_CONTROLLER+1,0x40);
  2019.  
  2020.    } // end else page 1
  2021. else
  2022. if (page==PAGE_2)
  2023.    {
  2024.    // re-program the start address registers in the CRT controller
  2025.    // to point at page 1 @ 0xA000:8000
  2026.  
  2027.    // first low byte of address
  2028.  
  2029.    _outp(CRT_CONTROLLER,CRT_ADDR_LOW);
  2030.    _outp(CRT_CONTROLLER+1,0x00);
  2031.  
  2032.    // now high byte
  2033.  
  2034.    _outp(CRT_CONTROLLER,CRT_ADDR_HI);
  2035.    _outp(CRT_CONTROLLER+1,0x80);
  2036.  
  2037.    } // end else page 2
  2038. else
  2039. if (page==PAGE_3)
  2040.    {
  2041.    // re-program the start address registers in the CRT controller
  2042.    // to point at page 1 @ 0xA000:C000
  2043.  
  2044.    // first low byte of address
  2045.  
  2046.    _outp(CRT_CONTROLLER,CRT_ADDR_LOW);
  2047.    _outp(CRT_CONTROLLER+1,0x00);
  2048.  
  2049.    // now high byte
  2050.  
  2051.    _outp(CRT_CONTROLLER,CRT_ADDR_HI);
  2052.    _outp(CRT_CONTROLLER+1,0xC0);
  2053.  
  2054.    } // end else page 3
  2055.  
  2056. // note: we could use WORD out's, but this is clearer, feel free to change them
  2057.  
  2058. } // end Set_Visual_Page_Mode_Y
  2059.  
  2060. ///////////////////////////////////////////////////////////////////////////////
  2061.  
  2062. void Set_Visual_Page_Mode_Y_Half(int page)
  2063. {
  2064. // THIS VERSION OF THE FUNCTION SAVES AN OUTS WORTH OF COMPUTER CYCLES!!!
  2065.  
  2066. // this function sets the visual page that will be displayed by the VGA
  2067.  
  2068. if (page==PAGE_0)
  2069.    {
  2070.    // re-program the start address registers in the CRT controller
  2071.    // to point at page 0 @ 0xA000:0000
  2072.  
  2073.    // SINCE THE LOW BYTE DOESN'T CHANGE IN THIS CONFIGURATION, I'LL
  2074.    // COMMENT OUT THE LOW BYTE STUFF...
  2075.  
  2076.    // first low byte of address
  2077.  
  2078. //   _outp(CRT_CONTROLLER,CRT_ADDR_LOW);
  2079. //   _outp(CRT_CONTROLLER+1,0x00);
  2080.  
  2081.    // now high byte
  2082.  
  2083.    _outp(CRT_CONTROLLER,CRT_ADDR_HI);
  2084.    _outp(CRT_CONTROLLER+1,0x00);
  2085.  
  2086.    } // end if page 0
  2087. else
  2088. if (page==PAGE_1)
  2089.    {
  2090.    // re-program the start address registers in the CRT controller
  2091.    // to point at page 1 @ 0xA000:4000
  2092.  
  2093.    // first low byte of address
  2094.  
  2095. //   _outp(CRT_CONTROLLER,CRT_ADDR_LOW);
  2096. //   _outp(CRT_CONTROLLER+1,0x00);
  2097.  
  2098.    // now high byte
  2099.  
  2100.    _outp(CRT_CONTROLLER,CRT_ADDR_HI);
  2101.    _outp(CRT_CONTROLLER+1,0x40);
  2102.  
  2103.    } // end else page 1
  2104. if (page==PAGE_2)
  2105.    {
  2106.    // re-program the start address registers in the CRT controller
  2107.    // to point at page 1 @ 0xA000:8000
  2108.  
  2109.    // first low byte of address
  2110.  
  2111. //   _outp(CRT_CONTROLLER,CRT_ADDR_LOW);
  2112. //   _outp(CRT_CONTROLLER+1,0x00);
  2113.  
  2114.    // now high byte
  2115.  
  2116.    _outp(CRT_CONTROLLER,CRT_ADDR_HI);
  2117.    _outp(CRT_CONTROLLER+1,0x80);
  2118.  
  2119.    } // end else page 2
  2120. if (page==PAGE_3)
  2121.    {
  2122.    // re-program the start address registers in the CRT controller
  2123.    // to point at page 1 @ 0xA000:C000
  2124.  
  2125.    // first low byte of address
  2126.  
  2127. //   _outp(CRT_CONTROLLER,CRT_ADDR_LOW);
  2128. //   _outp(CRT_CONTROLLER+1,0x00);
  2129.  
  2130.    // now high byte
  2131.  
  2132.    _outp(CRT_CONTROLLER,CRT_ADDR_HI);
  2133.    _outp(CRT_CONTROLLER+1,0xC0);
  2134.  
  2135.    } // end else page 3
  2136.  
  2137.  
  2138. } // end Set_Visual_Page_Mode_Y_Half
  2139.  
  2140. ///////////////////////////////////////////////////////////////////////////////
  2141.  
  2142. void Set_Working_Page_Mode_Y(int page)
  2143. {
  2144. // this function sets the page that all MODE Y functions will update when
  2145. // called
  2146.  
  2147. if (page==PAGE_0)
  2148.    video_buffer = pagey_0_buffer;
  2149. else
  2150. if (page==PAGE_1)
  2151.    video_buffer = pagey_1_buffer;
  2152. else
  2153. if (page==PAGE_2)
  2154.    video_buffer = pagey_2_buffer;
  2155. else
  2156. if (page==PAGE_3)
  2157.    video_buffer = pagey_3_buffer;
  2158.  
  2159. } // end Set_Working_Page_Mode_Y
  2160.  
  2161. // THESE LAST FEW FUNCTION WERE USED FOR 'SLOW RUNNINGS', THEY ARE A LITTLE
  2162. // BIT APPLICATION SPECIFIC, BUT i COULDN'T THINK OF ANYWHERE ELSE TO PUT
  2163. // THEM.
  2164.  
  2165. void PCX_Copy_To_Video_Mem(pcx_picture_ptr image, unsigned char far *dest)
  2166. {
  2167. // This function copies a PCX PICTURE into a region of memory that will
  2168. // not be displayed.
  2169.  
  2170.     int x_index;            // looping variable
  2171.     int y_index;            // looping variable
  2172.  
  2173.     unsigned int image_buffer_offset; // offset into image to be copied
  2174.     unsigned int vid_offset;          // offset into never displayed memory
  2175.  
  2176.     for (x_index = 0; x_index<320; x_index++)
  2177.     {
  2178.         // first select the proper color plane to write to...
  2179.         // I could have written to one plane at a time but - Oh Hell!...
  2180.  
  2181.         _asm
  2182.         {
  2183.            mov dx,SEQUENCER          ; address the sequencer
  2184.            mov al,SEQ_PLANE_ENABLE   ; select the plane enable register
  2185.            mov cl,BYTE PTR x_index   ; extract lower byte from x
  2186.            and cl,03h                ; extract the plane number = x MOD 4
  2187.            mov ah,1                  ; a "1" selects the plane in the plane enable
  2188.            shl ah,cl                 ; shift the "1" bit proper number of times
  2189.            out dx,ax                 ; do it baby!
  2190.         } // end asm
  2191.  
  2192.         for (y_index = 0; y_index<200; y_index++)
  2193.         {
  2194.             image_buffer_offset = (y_index<<8) + (y_index<<6) + x_index;
  2195.  
  2196.             vid_offset = (y_index<<6) + (y_index<<4) + (x_index>>2);
  2197.  
  2198.             dest[vid_offset] =
  2199.                                 image->buffer[image_buffer_offset];
  2200.         }
  2201.     }
  2202. } // end PCX_Copy_To_Video_Mem
  2203.  
  2204. void Copy_From_Unseen_Vram_to_Page(unsigned char far *buffer1, unsigned char far *buffer2,int to_row)
  2205. {
  2206.     // this function copies a [mode Y] screen full 'o data from the area of
  2207.     // memory pointed to by 'buffer', and copies it to the page pointed to by
  2208.     // 'buffer2' (usually PAGE 0 or PAGE 1)...
  2209.  
  2210.     // THIS IS MY FIRST REAL   W R I T E   M O D E   O N E     experiment!
  2211.  
  2212.     // The function uses WRITE MODE ONE to copy all four planes at ONCE!
  2213.  
  2214.     unsigned int ModeRegTemp;
  2215.  
  2216.     unsigned char pixel_color;
  2217.  
  2218.     unsigned char far *buff2;
  2219.     unsigned char far *buff1;
  2220.     int xw,yw;
  2221.  
  2222.     // Write Mode ONE...
  2223.  
  2224.     _outp(GFX_CONTROLLER, GFX_WRITE_MODE);
  2225.  
  2226.     ModeRegTemp = _inp(GC_DATA_REG);
  2227.     ModeRegTemp = (ModeRegTemp & 0xFC) | 0x01;
  2228.     _outp(GC_DATA_REG, ModeRegTemp);
  2229.  
  2230.     // ... and the stuff
  2231.  
  2232.     buff1 = buffer1;
  2233.     buff2 = buffer2;
  2234.  
  2235.     // enable all planes
  2236.  
  2237.     _asm
  2238.     {
  2239.         mov dx,SEQUENCER
  2240.         mov al,SEQ_PLANE_ENABLE
  2241.         mov ah,0x0f
  2242.         out dx,ax
  2243.     }
  2244.  
  2245.     for (yw = 0; yw<to_row; yw++)
  2246.     {
  2247.         for (xw = 0; xw < 80; xw++)
  2248.         {
  2249.             *buff2=*buff1;
  2250.             buff2++;
  2251.             buff1++;
  2252.         }
  2253.     }
  2254.  
  2255.     // Now... leave WRITE MODE ONE!
  2256.  
  2257.     ModeRegTemp &= 0xFC;
  2258.  
  2259.     _outp(GFX_CONTROLLER, GFX_WRITE_MODE);
  2260.     _outp(GC_DATA_REG, ModeRegTemp);
  2261.  
  2262. } // end Copy_From_Unseen_Vram_to_Page
  2263.  
  2264. void Planar_Special_Fade_to(unsigned char far *buffer1, unsigned char far *buffer2, int to_row)
  2265. {
  2266.     // this function copies a [mode Y] screen full 'o data from the area of
  2267.     // memory pointed to by 'buffer', and copies it to the page point to by
  2268.     // 'buffer2' (usually PAGE 0 or PAGE 1)...
  2269.  
  2270.           // THIS IS MY FIRST REAL   W R I T E    M O D E   O N E experiment!
  2271.  
  2272.     unsigned int ModeRegTemp;
  2273.  
  2274.     unsigned char pixel_color;
  2275.  
  2276.     unsigned char far *buff2;
  2277.     unsigned char far *buff1;
  2278.     int xw,yw;
  2279.  
  2280.     // Write Mode ONE...
  2281.  
  2282.     _outp(GFX_CONTROLLER, GFX_WRITE_MODE);
  2283.  
  2284.     ModeRegTemp = _inp(GC_DATA_REG);
  2285.     ModeRegTemp = (ModeRegTemp & 0xFC) | 0x01;
  2286.     _outp(GC_DATA_REG, ModeRegTemp);
  2287.  
  2288.     // ... and the stuff
  2289.  
  2290.     buff1 = buffer1;
  2291.     buff2 = buffer2;
  2292.  
  2293.     _asm
  2294.     {
  2295.         mov dx,SEQUENCER
  2296.         mov al,SEQ_PLANE_ENABLE
  2297.         mov ah,0x08
  2298.         out dx,ax
  2299.     }
  2300.  
  2301.     for (yw = 0; yw<to_row; yw++)
  2302.     {
  2303.         for (xw = 0; xw < 80; xw++)
  2304.         {
  2305.             *buff2=*buff1;
  2306.             buff2++;
  2307.             buff1++;
  2308.         }
  2309.     }
  2310.  
  2311.     buff1 = buffer1;
  2312.     buff2 = buffer2;
  2313.  
  2314.     _asm
  2315.     {
  2316.         les di,buff1
  2317.         mov dx,SEQUENCER          // address the sequencer
  2318.         mov al,SEQ_PLANE_ENABLE   // select the plane enable register
  2319.         mov ah,0x04                  // a "1" selects the plane in the plane enable
  2320.         out dx,ax                 // do it baby!
  2321.     } // end asm
  2322.  
  2323.     for (yw = 0; yw<to_row; yw++)
  2324.     {
  2325.         for (xw = 0; xw < 80; xw++)
  2326.         {
  2327.             *buff2=*buff1;
  2328.             buff2++;
  2329.             buff1++;
  2330.  
  2331.         }
  2332.     }
  2333.  
  2334.     buff1 = buffer1;
  2335.     buff2 = buffer2;
  2336.  
  2337.     _asm
  2338.     {
  2339.         mov dx,SEQUENCER          // address the sequencer
  2340.         mov al,SEQ_PLANE_ENABLE   // select the plane enable register
  2341.         mov ah,0x02                  // a "1" selects the plane in the plane enable
  2342.         out dx,ax                 // do it baby!
  2343.     } // end asm
  2344.  
  2345.     for (yw = 0; yw<to_row; yw++)
  2346.     {
  2347.         for (xw = 0; xw < 80; xw++)
  2348.         {
  2349.             *buff2=*buff1;
  2350.             buff2++;
  2351.             buff1++;
  2352.  
  2353.         }
  2354.     }
  2355.  
  2356.     buff1 = buffer1;
  2357.     buff2 = buffer2;
  2358.  
  2359.     _asm
  2360.     {
  2361.         mov dx,SEQUENCER          // address the sequencer
  2362.         mov al,SEQ_PLANE_ENABLE   // select the plane enable register
  2363.         mov ah,0x01                  // a "1" selects the plane in the plane enable
  2364.         out dx,ax                 // do it baby!
  2365.     } // end asm
  2366.  
  2367.     for (yw = 0; yw<to_row; yw++)
  2368.     {
  2369.         for (xw = 0; xw < 80; xw++)
  2370.         {
  2371.             *buff2=*buff1;
  2372.             buff2++;
  2373.             buff1++;
  2374.  
  2375.         }
  2376.     }
  2377.  
  2378.     // Now... leave WRITE MODE ONE!
  2379.  
  2380.     ModeRegTemp &= 0xFC;
  2381.  
  2382.     _outp(GFX_CONTROLLER, GFX_WRITE_MODE);
  2383.     _outp(GC_DATA_REG, ModeRegTemp);
  2384.  
  2385. } // end Planar_Special_Fade_to
  2386.